import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;



public class TextBuddy {
	
	
	private static Path file;
	private static String fileName;
	private static String fileDir;
	private static ArrayList<String> fileContent = null;
	private static Scanner scanner = new Scanner(System.in);
	private static final int ARRAY_LENGTH_WITH_PAR = 2;	
	private static ArrayList<String> VALID_CMDS = new ArrayList<String>(Arrays.asList("add", "clear", "display", "delete", "exit", "sort", "search"));
	private static final String INVALID_CMD = "Invalid Command";
	private static final String INVALID_PAR = "Invalid Parameter";
	private static final String WAIT_COMMAND = "command: ";
	private static final String TEST_FILE_DIR = "test.txt";
	private static final int TEST_INIT_ARGS_LENGTH = 1;
	private static final int CMD_POSITION = 0;

	public static void main(String[] args) throws IOException {
		init(args);
		while (true) {
			String command = requestCommand();
			String feedback = processCommand(command);
			System.out.println(feedback);
		}
	}
	
	public static String testCommand(String command) throws IOException{
		String[] initArguments = new String[TEST_INIT_ARGS_LENGTH];
		initArguments[CMD_POSITION] = TEST_FILE_DIR;
		init(initArguments);
		String feedback = processCommand(command);
		return feedback;
	}

	private static String processCommand(String command) throws IOException {
		String feedback = new String();
		if (isValidCommand(command)){
			String command_type = identifyCommandType(command);
			String parameter = getParameter(command, command_type);
			feedback = executeCommand(command_type, parameter);
		} else {
			feedback = INVALID_CMD;
		}
		return feedback;
	}

	private static String executeCommand(String commandType, String parameter) throws IOException {
		String feedback = new String();
		if(commandType.equals("add")) {
			feedback = addLine(parameter);
		} else if (commandType.equals("delete")) {
			feedback = deleteLine(parameter);
		} else if (commandType.equals("search")) {
			feedback = searchLine(parameter);
		} else if (commandType.equals("clear") && parameter == null) {
			feedback = clearLines(parameter);
		} else if (commandType.equals("display") && parameter == null) {
			feedback = displayLines(parameter);
		} else if (commandType.equals("sort") && parameter == null) {
			feedback = sortLines(parameter);
		} else if (commandType.equals("exit") && parameter == null) {
			System.exit(1);
		} else {
			feedback = INVALID_CMD;
		}
		
		return feedback;
	}

	private static String searchLine(String parameter) {
		
		String feedback = new String();
		String searchWord = parameter;
		
		for (int i = 0; i < fileContent.size(); i++){
			String line = fileContent.get(i);
			if(line.equals(parameter)){
				int linePosition = i + 1;
				feedback = "search found: " + linePosition + ". " + parameter;
				return feedback;
			}
		}
		feedback = "\"" + searchWord + "\" is not found in " + fileName;
		return feedback;
	}

	private static String sortLines(String parameter) throws IOException {
		
		String feedback = new String();
		
		clearFileContent();
		Collections.sort(fileContent);
		for (java.util.Iterator<String> i = fileContent.iterator(); i.hasNext(); ){
			String line = i.next();
			writeContent(line);
		}
		feedback = fileName + " has been sorted";
		updateFileContent();
		return feedback;
	}

	private static String deleteLine(String parameter) {
		String feedback = new String();
		
		if(isValidDelete(parameter)){
			int linePosition = Integer.parseInt(parameter) - 1;
			try {
			
				String lineToRemove = fileContent.get(linePosition);
				FileWriter clear = new FileWriter(fileDir);
				clear.write("");
				clear.close();
				for(int i = 0; i < fileContent.size(); i++){
	            	if (i != linePosition){
	            		FileWriter out = new FileWriter(fileDir, true);
	    				out.write(fileContent.get(i) + "\r\n");
	    				out.close();
	            	}
            	}
				
				feedback = "deleted from " + fileName + ": \"" + lineToRemove + "\"";
				updateFileContent();
			
			} catch (IOException e){
				
			}
		}else {
			feedback = INVALID_CMD;
		}
		return feedback;
	}

	private static boolean isValidDelete(String parameter) {
		try { 
	        int par_int = Integer.parseInt(parameter); 
	        if (par_int > fileContent.size()){
	        	return false;
	        } else if (par_int <= 0 ){
	        	return false;
	        }
	    } catch(NumberFormatException e) { 
	        return false; 
	    }
	    return true;
	}

	private static String addLine(String parameter) {
		String feedback = new String();
		if(parameter != null){
			try {
				writeContent(parameter);
				feedback = "added to " + fileName + ": \"" + parameter + "\"";
				updateFileContent();
			} catch (IOException e) {
				
			}
			
		} else {
			feedback = INVALID_PAR;
		}
		return feedback;
	}

	private static void writeContent(String parameter) throws IOException {
		FileWriter out = new FileWriter(fileDir, true);
		out.write(parameter + "\r\n");
		out.close();
	}

	private static String clearLines(String parameter) {
		String feedback = new String();
		
		try {
			clearFileContent();
			updateFileContent();
	        feedback = "all content deleted from " + fileName;
	    } catch (IOException e) {}
		return feedback;
	}

	private static void clearFileContent() throws IOException {
		BufferedWriter out = new BufferedWriter(new FileWriter(fileDir));
		out.write("");
		out.close();
	}

	private static String displayLines(String parameter) {
		String feedback = new String();
		if(fileContent.size() == 0){
			feedback = fileName + " is empty";
		} else {
			int line_num = 1;
			for(String s: fileContent){
				feedback = feedback + (line_num + ". " + s + "\n");
				line_num ++;
			}
		}
		return feedback;
	}

	private static String getParameter(String command, String commandType) {
		String[] commandArray = command.split(commandType + " ");
		String parameter;
		if(commandArray.length < ARRAY_LENGTH_WITH_PAR){
			parameter = null;
		} else {
			parameter = commandArray[1];
		}
		return parameter;
	}

	private static String identifyCommandType(String command) {
		String[] commandArray = command.split(" ");
		String commandType = commandArray[CMD_POSITION];
		return commandType;
	}

	private static boolean isValidCommand(String command) {
		if (command == null){
			return false;
		} else {
			String commandType = command.split(" ")[0];
			if ( VALID_CMDS.contains(commandType)) {
				return true;
			}
		}
		return false;
	}

	private static String requestCommand() {
		System.out.print(WAIT_COMMAND);
		String command = scanner.nextLine();  
	    return command;
	}

	static void init(String[] args) throws IOException {
		if (isValidArg(args)){
			String dir = getFileDirectory(args);
			setTargetFile(dir);
			getFilename();
			updateFileContent();
			System.out.println("Welcome to TextBuddy. " + fileName + " is ready for use.");
		} else {
			System.out.println("Invalid Arguments");
		}
	}

	private static void updateFileContent() throws IOException {
		ArrayList<String> bufferContent = new ArrayList<String>();
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(fileDir));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		String line;
		while ((line = br.readLine()) != null) {
			bufferContent.add(line);
		}
		br.close();	
		fileContent = bufferContent;		
	}

	private static void setTargetFile(String dir) {
		if (dir != null) {
			file = Paths.get(dir);
		}
	}

	private static void getFilename() {
		fileName = file.getFileName().toString();
	}

	private static String getFileDirectory(String[] args) {
		fileDir = args[0];
		return fileDir;
	}

	private static boolean isValidArg(String[] args) {
		if (args.length == 1) {
			return true;
		}
		return false;
	}
}
